package com.UnionPayCenter.controller;

import com.UnionPayCenter.account.enums.BillDutyEnum;
import com.UnionPayCenter.entity.ResponseWrapper;
import com.UnionPayCenter.entity.UserEntity;
import com.UnionPayCenter.entity.dto.BalancePayRequest;
import com.UnionPayCenter.entity.dto.CommonPayRequest;
import com.UnionPayCenter.entity.dto.FundsPayDTO;
import com.UnionPayCenter.entity.dto.FundsQueryRequest;
import com.UnionPayCenter.entity.dto.TransferCouponsRequest;
import com.UnionPayCenter.entity.vo.FundsBillRecordVo;
import com.UnionPayCenter.enums.ErrorCodeEnum;
import com.UnionPayCenter.exception.ApiException;
import com.UnionPayCenter.jwt.CurrentManager;
import com.UnionPayCenter.jwt.CurrentShop;
import com.UnionPayCenter.service.FundsAccountService;
import com.UnionPayCenter.service.IUserService;
import com.UnionPayCenter.sms.StringUtil;
import com.UnionPayCenter.swagger.ApiJsonObject;
import com.UnionPayCenter.swagger.ApiJsonProperty;
import com.UnionPayCenter.util.Asserts;
import com.UnionPayCenter.util.DateFormatUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Objects;

/**
 * @author Noah
 * @since 1.0.0, 2019/05/18
 */
@Slf4j
@Api(value = "funds", tags = "资金账户---所有金额相关的单位为:分")
@RestController
@RequestMapping("/funds")
public class FundsAccountController {

    @Autowired
    private FundsAccountService fundsAccountService;

    @Autowired
    private IUserService userService;

    @RequestMapping(value = "user/account/list", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]获取资金流水", response = FundsBillRecordVo.class)
    public ResponseWrapper listUserFundsRecord(@ApiJsonObject(name = "fundsQueryParams",
            value = {@ApiJsonProperty(key = "userId", value = "用户ID"),
                    @ApiJsonProperty(key = "type", value = "流水类型 1:充值,2:消费 ",
                            required = false),
                    @ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "page", value = "页数", type = "int"),
                    @ApiJsonProperty(key = "pageSize", value = "每页条数", type = "int")})
                                               @RequestBody JSONObject jsonParam) {
        String userId = (String) jsonParam.get("userId");
        String type = (String) jsonParam.get("type");
        String shopId = (String) jsonParam.get("shopId");
        Integer page = jsonParam.get("page") == null ? 0 : (Integer) jsonParam.get("page");
        Integer pageSize = jsonParam.get("pageSize") == null ? 10 : (Integer) jsonParam.get("pageSize");
        Asserts.notBlank(userId, "用户ID");
        try {
            FundsQueryRequest request = FundsQueryRequest.builder().build();
            return ResponseWrapper.succeed(fundsAccountService.listAllBillByUserId(userId, shopId, page, pageSize, type, request));
        } catch (ApiException e) {
            log.error(String.format("[前端]获取资金流水，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]获取资金流水"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }


    @CurrentShop
    @RequestMapping(value = "user/deposit/list", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]获取用户充值流水", response = FundsBillRecordVo.class)
    public ResponseWrapper listUserDepositRecordForBack(@ApiJsonObject(name = "fundsUserDepositListParams",
            value = {@ApiJsonProperty(key = "userId", value = "用户ID"),
                    @ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "page", value = "页数", type = "int"),
                    @ApiJsonProperty(key = "pageSize", value = "每页条数", type = "int")})
                                                        @RequestBody JSONObject jsonParam) {
        String userId = (String) jsonParam.get("userId");
        String shopId = (String) jsonParam.get("shopId");
        Integer page = jsonParam.get("page") == null ? 0 : (Integer) jsonParam.get("page");
        Integer pageSize = jsonParam.get("pageSize") == null ? 10 : (Integer) jsonParam.get("pageSize");
        try {
            FundsQueryRequest request = FundsQueryRequest.builder().build();
            return ResponseWrapper.succeed(fundsAccountService.listDepositByUserIdFront(userId, shopId, page, pageSize, "1", request));
        } catch (ApiException e) {
            log.error(String.format("[前端]获取充值流水，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]获取充值流水"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }

    @CurrentManager
    @CurrentShop
    @RequestMapping(value = "back/account/list", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[后台]获取用户资金流水", response = FundsBillRecordVo.class)
    public ResponseWrapper listUserFundsRecordForBack(@ApiJsonObject(name = "fundsQueryBackParams",
            value = {@ApiJsonProperty(key = "userId", value = "用户ID", required = false),
                    @ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "mobile", value = "手机号,有userid,优先使用userid", required = false),
                    @ApiJsonProperty(key = "type", value = "流水类型 1:支付,2:充值 ",
                            required = false),
                    @ApiJsonProperty(key = "startTime", value = "开始时间", required = false),
                    @ApiJsonProperty(key = "endTime", value = "结束时间", required = false),
                    @ApiJsonProperty(key = "page", value = "页数", type = "int"),
                    @ApiJsonProperty(key = "pageSize", value = "每页条数", type = "int")})
                                                      @RequestBody JSONObject jsonParam) {
        String userId = (String) jsonParam.get("userId");
        String type = (String) jsonParam.get("type");
        String mobile = (String) jsonParam.get("mobile");
        String shopId = (String) jsonParam.get("shopId");
        String startTime = (String) jsonParam.get("startTime");
        String endTime = (String) jsonParam.get("endTime");
        Integer page = jsonParam.get("page") == null ? 0 : (Integer) jsonParam.get("page");
        Integer pageSize = jsonParam.get("pageSize") == null ? 10 : (Integer) jsonParam.get("pageSize");

        if (StringUtils.isBlank(userId) && StringUtils.isNotBlank(mobile)) {
            UserEntity userEntity = userService.getUserByMobile(mobile, Integer.valueOf(shopId));
            if (null == userEntity) {
                return ResponseWrapper.succeed(ErrorCodeEnum.SC0);
            }
        }
        try {
            FundsQueryRequest request = FundsQueryRequest.builder().startTime(StringUtils.isNotBlank(startTime) ?
                    DateFormatUtil.stringToDate(startTime) : null)
                    .endTime(StringUtils.isNotBlank(endTime) ? DateFormatUtil.stringToDate(endTime) : null).build();
            return ResponseWrapper.succeed(fundsAccountService.listAllBillByUserId(userId, shopId, page, pageSize, type, request));
        } catch (ApiException e) {
            log.error(String.format("[前端]获取资金流水，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("[前端]获取资金流水", e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }

    @CurrentShop
    @CurrentManager
    @RequestMapping(value = "back/account/export", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[后台]用户资金流水导出", response = String.class)
    public ResponseWrapper exportModel(
            @ApiJsonObject(name = "fundsQueryBackExportParams", value = {@ApiJsonProperty(key = "userId", value = "用户ID", required = false),
                    @ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "mobile", value = "手机号,有userid,优先使用userid", required = false),
                    @ApiJsonProperty(key = "type", value = "流水类型 1:支付,2:充值  ",
                            required = false),
                    @ApiJsonProperty(key = "startTime", value = "开始时间", required = false),
                    @ApiJsonProperty(key = "endTime", value = "结束时间", required = false),
                    @ApiJsonProperty(key = "page", value = "页数", type = "int"),
                    @ApiJsonProperty(key = "pageSize", value = "每页条数", type = "int")})
            @RequestBody JSONObject jsonParam) {
        try {
            String userId = (String) jsonParam.get("userId");
            String type = (String) jsonParam.get("type");
            String mobile = (String) jsonParam.get("mobile");
            String shopId = (String) jsonParam.get("shopId");
            String startTime = (String) jsonParam.get("startTime");
            String endTime = (String) jsonParam.get("endTime");
            FundsQueryRequest request = FundsQueryRequest.builder().startTime(StringUtils.isNotBlank(startTime) ?
                    DateFormatUtil.stringToDate(startTime) : null)
                    .endTime(StringUtils.isNotBlank(endTime) ? DateFormatUtil.stringToDate(endTime) : null).build();
            String url = userService.exportUserFunds(fundsAccountService.listBillByUserId(userId, shopId, type, request));
            return ResponseWrapper.succeed(url);
        } catch (ApiException e) {
            log.error(String.format("[后台]用户资金流水导出失败，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("[后台]用户资金流水导出失败", e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }

    @CurrentManager
    @CurrentShop
    @RequestMapping(value = "third/account/export", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[后台]导出用户第三方交易流水", response = FundsBillRecordVo.class)
    public ResponseWrapper exportthirdFundsRecordForBack(@ApiJsonObject(name = "fundsExportthirdParams",
            value = {@ApiJsonProperty(key = "userId", value = "用户ID", required = false),
                    @ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "type", value = "流水类型 1:充值,2:充值并支付,3:支付,4:活动优惠金额,5:用户导入  ",
                            required = false),
                    @ApiJsonProperty(key = "mobile", value = "手机号,有userid,优先使用userid", required = false),
                    @ApiJsonProperty(key = "startTime", value = "开始时间", required = false),
                    @ApiJsonProperty(key = "endTime", value = "结束时间", required = false)})
                                                         @RequestBody JSONObject jsonParam) {
        String userId = (String) jsonParam.get("userId");
        String mobile = (String) jsonParam.get("mobile");
        String shopId = (String) jsonParam.get("shopId");
        String startTime = (String) jsonParam.get("startTime");
        String endTime = (String) jsonParam.get("endTime");
        Integer type = jsonParam.getInteger("type");
        if (Objects.nonNull(startTime)) {
            startTime = startTime + " 00:00:00";
        }
        if (Objects.nonNull(endTime)) {
            endTime = endTime + " 23:59:59";
        }

        if (StringUtils.isBlank(userId) && StringUtils.isNotBlank(mobile)) {
            UserEntity userEntity = userService.getUserByMobile(mobile, Integer.valueOf(shopId));
            if (null == userEntity) {
                return ResponseWrapper.succeed(ErrorCodeEnum.SC0);
            }
        }
        try {

            FundsQueryRequest request = FundsQueryRequest.builder().startTime(StringUtils.isNotBlank(startTime) ?
                    DateFormatUtil.stringToDate(startTime) : null)
                    .type(type == null ? null : BillDutyEnum.getEnum(type))
                    .endTime(StringUtils.isNotBlank(endTime) ? DateFormatUtil.stringToDate(endTime) : null)
                    .userId(userId)
                    .shopId(shopId)
                    .page(1)
                    .pageSize(1000000)
                    .build();

            PageInfo<FundsBillRecordVo> list = fundsAccountService.listDepositByUserId(request);
            String url = userService.exportThirdFunds(list.getList());
            return ResponseWrapper.succeed(url);
        } catch (ApiException e) {
            log.error(String.format("[前端]获取用户充值流水，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]获取用户充值流水"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }

    @CurrentManager
    @CurrentShop
    @RequestMapping(value = "third/account/list", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[后台]获取用户充值流水", response = FundsBillRecordVo.class)
    public ResponseWrapper listthirdFundsRecordForBack(@ApiJsonObject(name = "fundsQuerythirdParams",
            value = {@ApiJsonProperty(key = "userId", value = "用户ID", required = false),
                    @ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "mobile", value = "手机号,有userid,优先使用userid", required = false),
                    @ApiJsonProperty(key = "type", value = "流水类型 1:充值,2:充值并支付,3:支付,4:活动优惠金额,5:用户导入  ",
                            required = false),
                    @ApiJsonProperty(key = "startTime", value = "开始时间", required = false),
                    @ApiJsonProperty(key = "endTime", value = "结束时间", required = false),
                    @ApiJsonProperty(key = "page", value = "页数", type = "int"),
                    @ApiJsonProperty(key = "pageSize", value = "每页条数", type = "int")})
                                                       @RequestBody JSONObject jsonParam) {
        String userId = (String) jsonParam.get("userId");
        String mobile = (String) jsonParam.get("mobile");
        String shopId = (String) jsonParam.get("shopId");
        String startTime = (String) jsonParam.get("startTime");
        String endTime = (String) jsonParam.get("endTime");
        Integer type = jsonParam.getInteger("type");
        if (Objects.nonNull(startTime)) {
            startTime = startTime + " 00:00:00";
        }
        if (Objects.nonNull(endTime)) {
            endTime = endTime + " 23:59:59";
        }

        Integer page = jsonParam.get("page") == null ? 0 : (Integer) jsonParam.get("page");
        Integer pageSize = jsonParam.get("pageSize") == null ? 10 : (Integer) jsonParam.get("pageSize");
        if (StringUtils.isBlank(userId) && StringUtils.isNotBlank(mobile)) {
            UserEntity userEntity = userService.getUserByMobile(mobile, Integer.valueOf(shopId));
            if (null == userEntity) {
                userId = "999999999";
            }
        }
        try {
            FundsQueryRequest request = FundsQueryRequest.builder().startTime(StringUtils.isNotBlank(startTime) ?
                    DateFormatUtil.stringToDate(startTime) : null)
                    .endTime(StringUtils.isNotBlank(endTime) ? DateFormatUtil.stringToDate(endTime) : null)
                    .type(type == null ? null : BillDutyEnum.getEnum(type))
                    .userId(userId)
                    .shopId(shopId)
                    .pageSize(pageSize)
                    .page(page)
                    .sumOrNot(true)
                    .build();

            return ResponseWrapper.succeed(fundsAccountService.listDepositByUserId(request));
        } catch (ApiException e) {
            log.error(String.format("[前端]获取用户充值流水，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]获取用户充值流水"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }


    @CurrentManager
    @CurrentShop
    @RequestMapping(value = "user/account/info", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[后台]获取用户资金流水", response = String.class)
    public ResponseWrapper getFundsRecordInfoForBack(@ApiJsonObject(name = "fundsQueryInfoParams",
            value = {@ApiJsonProperty(key = "userId", value = "用户ID", required = false),
                    @ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "serialNumber", value = "流水ID"),
            })
                                                     @RequestBody JSONObject jsonParam) {
        String userId = (String) jsonParam.get("userId");
        String mobile = (String) jsonParam.get("mobile");
        String shopId = (String) jsonParam.get("shopId");
        String serialNumber = (String) jsonParam.get("serialNumber");


        try {
            return ResponseWrapper.succeed(fundsAccountService.getBySn(userId, serialNumber));
        } catch (ApiException e) {
            log.error(String.format("[前端]获取资金流水，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error("[前端]获取资金流水", e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }


    /**
     * 余额支付
     *
     * @param balancePayRequest
     * @return
     */
    @CurrentShop
    @RequestMapping(value = "user/account/smspay", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]带验证码校验的余额支付", response = String.class)
    public ResponseWrapper balancePay(@ApiParam(name = "fundsChangeSmspayParams") @RequestBody(required = false) BalancePayRequest balancePayRequest) {

        String smsCode = balancePayRequest.getSmscode();
        String mobile = balancePayRequest.getMobile();
        Asserts.notBlank(smsCode, "短信验证码");
        Asserts.notBlank(mobile, "手机号");
        if (!userService.checkVerificationCode(mobile, smsCode, 1)) {
            return ResponseWrapper.failed(ErrorCodeEnum.SW400);
        }

        checkPayParams(balancePayRequest);
        processDefaultVaule(balancePayRequest);


        try {
            FundsPayDTO payDTO = assembleFundsPay(balancePayRequest);
            fundsAccountService.balancePay(payDTO);
            return ResponseWrapper.succeed(ErrorCodeEnum.SC0);
        } catch (ApiException e) {
            log.error(String.format("[前端]用户支付不成功，参数:%s, 错误信息:%s", JSONObject.toJSONString(balancePayRequest), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]用户支付出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }


    /**
     * 银联支付
     *
     * @param unionPayRequest
     * @return
     */
    @CurrentShop
    @RequestMapping(value = "user/account/unionpay", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]带验证码校验的银联支付", response = String.class)
    public ResponseWrapper unionpay(@ApiParam(name = "fundsChangeUnionpayParams") @RequestBody(required = false) CommonPayRequest unionPayRequest) {

        checkPayParams(unionPayRequest);
        processDefaultVaule(unionPayRequest);

        try {
            FundsPayDTO payDTO = assembleFundsPay(unionPayRequest);
            return ResponseWrapper.succeed(fundsAccountService.unionPay(payDTO));
        } catch (ApiException e) {
            log.error(String.format("[前端]用户微信支付不成功，参数:%s, 错误信息:%s", JSONObject.toJSONString(unionPayRequest), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]用户微信支付出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }


    /**
     * 微信支付
     *
     * @param wechatPayRequest
     * @return
     */
    @CurrentShop
    @RequestMapping(value = "user/account/wechatsmspay", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]带验证码校验的微信支付", response = String.class)
    public ResponseWrapper wechatsmspay(@ApiParam(name = "fundsChangeSmspayParams") @RequestBody(required = false) CommonPayRequest wechatPayRequest) {

        checkPayParams(wechatPayRequest);
        processDefaultVaule(wechatPayRequest);

        try {
            FundsPayDTO payDTO = assembleFundsPay(wechatPayRequest);
            return ResponseWrapper.succeed(fundsAccountService.wechatPay(payDTO));
        } catch (ApiException e) {
            log.error(String.format("[前端]用户微信支付不成功，参数:%s, 错误信息:%s", JSONObject.toJSONString(wechatPayRequest), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]用户微信支付出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }


    @CurrentShop
    @RequestMapping(value = "user/account/depositSmsPay", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]充值并支付", response = String.class)
    public ResponseWrapper depositPay(@ApiJsonObject(name = "fundsdepositSmsPayParams",
            value = {@ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "userId", value = "用户ID"),
                    @ApiJsonProperty(key = "smscode", value = "验证码"),
                    @ApiJsonProperty(key = "mobile", value = "手机号"),
                    @ApiJsonProperty(key = "remark", value = "备注", required = false),
                    @ApiJsonProperty(key = "totalAmount", value = "总计支付金额(单位:分)", type = "int"),
                    @ApiJsonProperty(key = "amount", value = "实际支付金额(单位:分)", type = "int"),
                    @ApiJsonProperty(key = "reduceAmount", value = "实际优惠金额(单位:分)", type = "int"),
                    @ApiJsonProperty(key = "serialNnumber", value = "流水号"),
                    @ApiJsonProperty(key = "status", value = "状态,银联支付状态"),
                    @ApiJsonProperty(key = "voucherId", value = "优惠券ID列表,多个分号分隔")}) @RequestBody
                                              JSONObject jsonParam) {

        String serialNnumber = (String) jsonParam.get("serialNnumber");
        String shopId = (String) jsonParam.get("shopId");
        String userId = (String) jsonParam.get("userId");
        Integer totalAmount = (Integer) jsonParam.get("totalAmount");
        Integer amount = (Integer) jsonParam.get("amount");
        Integer reduceAmount = (Integer) jsonParam.get("reduceAmount");
        String voucherId = (String) jsonParam.get("voucherId");
        String status = (String) jsonParam.get("status");
        String smsCode = (String) jsonParam.get("smscode");
        String mobile = (String) jsonParam.get("mobile");
        String remark = (String) jsonParam.get("remark");
        Asserts.notBlank(smsCode, "短信验证码");
        Asserts.notBlank(mobile, "手机号");
        Asserts.notBlank(shopId, "店铺ID");
        Asserts.notBlank(userId, "用户ID");
        Asserts.naturalNumber(totalAmount, "总计支付金额(分)");
        Asserts.naturalNumber(amount, "实际支付金额(分)");
        Asserts.naturalNumber(reduceAmount, "实际优惠金额(分)");
        Asserts.notBlank(serialNnumber, "充值流水号");
        Asserts.notBlank(status, "充值状态)");
        if (!userService.checkVerificationCode(mobile, smsCode, 1)) {
            return ResponseWrapper.failed(ErrorCodeEnum.SW400);
        }
        try {
            FundsPayDTO payDTO = new FundsPayDTO();
            payDTO.setAmount(amount);
            payDTO.setShopId(Integer.valueOf(shopId));
            payDTO.setTotalAmount(totalAmount);
            payDTO.setRemark(remark);
            if (StringUtils.isNotBlank(voucherId)) {
                payDTO.setDiscountId(voucherId.split(";")[0]);
            }
            payDTO.setOrderId(null);
            payDTO.setSerialNnumber(serialNnumber);
            payDTO.setStatus(status);
            fundsAccountService.depositPayFundsAccount(payDTO, userId, reduceAmount);
            return ResponseWrapper.succeed(ErrorCodeEnum.SC0);
        } catch (ApiException e) {
            log.error(String.format("[前端]用户消费不成功，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]用户消费出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }

    @CurrentShop
    @RequestMapping(value = "user/account/deposit", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]充值", response = String.class)
    public ResponseWrapper deposit(@ApiJsonObject(name = "fundsChangedepositParams",
            value = {@ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "userId", value = "用户ID"),
                    @ApiJsonProperty(key = "openId", value = "用户openId"),
                    @ApiJsonProperty(key = "amount", value = "金额(单位:分)", type = "int")}) @RequestBody
                                           JSONObject jsonParam) {
        String shopId = (String) jsonParam.get("shopId");
        String userId = (String) jsonParam.get("userId");
        Integer amount = (Integer) jsonParam.get("amount");
        String openId = (String) jsonParam.get("openId");
        Asserts.notBlank(shopId, "店铺ID");
        Asserts.notBlank(userId, "用户ID");
        Asserts.notBlank(openId, "用户openId");
        Asserts.naturalNumber(amount, "充值金额(分)");
        try {
            return ResponseWrapper.succeed(fundsAccountService.depositFundsAccount(shopId, userId, amount, openId));
        } catch (ApiException e) {
            log.error(String.format("[前端]用户充值不成功，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]用户充值出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }

    }

    @CurrentShop
    @RequestMapping(value = "user/account/wechatdeposit", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]微信充值", response = String.class)
    public ResponseWrapper wechatdeposit(@ApiJsonObject(name = "fundsChangeWechatDepositParams",
            value = {@ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "userId", value = "用户ID"),
                    @ApiJsonProperty(key = "openId", value = "微信openID"),
                    @ApiJsonProperty(key = "amount", value = "实际支付金额(单位:分)", type = "int")}) @RequestBody
                                                 JSONObject jsonParam) {

        String shopId = (String) jsonParam.get("shopId");
        String userId = (String) jsonParam.get("userId");
        Integer amount = (Integer) jsonParam.get("amount");
        String openId = (String) jsonParam.get("openId");

        Asserts.notBlank(shopId, "店铺ID");
        Asserts.notBlank(userId, "用户ID");
        Asserts.naturalNumber(amount, "充值金额(分)");

        try {
            FundsPayDTO payDTO = new FundsPayDTO();
            payDTO.setAmount(amount);
            payDTO.setShopId(Integer.valueOf(shopId));

            return ResponseWrapper.succeed(fundsAccountService.wechatDepositFundsAccount(shopId, userId, amount, openId));
        } catch (ApiException e) {
            log.error(String.format("[前端]用户微信支付不成功，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]用户微信支付出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }

    @CurrentShop
    @RequestMapping(value = "user/account/depositBack", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]充值回调", response = String.class)
    public ResponseWrapper depositBack(@ApiJsonObject(name = "fundsChangedepositBackParams",
            value = {@ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "serialNnumber", value = "流水号"),
                    @ApiJsonProperty(key = "status", value = "状态")}) @RequestBody
                                               JSONObject jsonParam) {
        String serialNnumber = (String) jsonParam.get("serialNnumber");
        String shopId = (String) jsonParam.get("shopId");
        String userId = (String) jsonParam.get("userId");
        String status = (String) jsonParam.get("status");
        Asserts.notBlank(shopId, "店铺ID");
        Asserts.notBlank(userId, "用户ID");
        Asserts.notBlank(serialNnumber, "充值流水号");
        Asserts.notBlank(status, "充值状态)");
        try {
            fundsAccountService.depositBackFundsAccount(shopId, userId, serialNnumber, status);
            return ResponseWrapper.succeed(ErrorCodeEnum.SC0);
        } catch (ApiException e) {
            log.error(String.format("[前端]用户充值不成功，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]用户充值出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }

    }

    @CurrentShop
    @RequestMapping(value = "user/voucher/list", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]获取所有优惠券", response = String.class)
    public ResponseWrapper listAllVouchers(@ApiJsonObject(name = "voucherQueryParams",
            value = {@ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "userId", value = "用户ID"),
                    @ApiJsonProperty(key = "payAmount", value = "支付金额(分)", type = "int", required = false),
                    @ApiJsonProperty(key = "status", value = "有效期类型 00可使用,01已使用,02过期 ",
                            required = false),
                    @ApiJsonProperty(key = "page", value = "页数", type = "int"),
                    @ApiJsonProperty(key = "pageSize", value = "每页条数", type = "int")})
                                           @RequestBody JSONObject jsonParam) {

        String shopId = (String) jsonParam.get("shopId");
        String userId = (String) jsonParam.get("userId");
        Asserts.notBlank(userId, "用户ID");
        Asserts.notBlank(shopId, "店铺ID");
        try {
            return ResponseWrapper.succeed(fundsAccountService.listAllVoucherByUserId(jsonParam));
        } catch (ApiException e) {
            log.error(String.format("[前端]获取优惠券信息不成功，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]获取优惠券信息出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }

    @CurrentShop
    @RequestMapping(value = "user/voucher/get", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]获取单张优惠券信息", response = String.class)
    public ResponseWrapper getVoucherInfo(@ApiJsonObject(name = "voucherQueryTicketParams",
            value = {@ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "userId", value = "用户ID"),
                    @ApiJsonProperty(key = "voucherId", value = "优惠券ID")}) @RequestBody
                                                  JSONObject jsonParam) {
        Integer userId = Integer.valueOf((String) jsonParam.get("userId"));
        String voucherId = (String) jsonParam.get("voucherId");
        Asserts.notNull(userId, "用户ID");
        Asserts.notBlank(voucherId, "优惠券ID");
        try {
            return ResponseWrapper.succeed(fundsAccountService.getUserCouponByDisId(userId, voucherId));
        } catch (ApiException e) {
            log.error(String.format("[前端]获取单张优惠券信息不成功，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]获取单张优惠券信息出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }

    @CurrentShop
    @RequestMapping(value = "user/voucher/cardById", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]获取会员卡信息", response = String.class)
    public ResponseWrapper getVoucherCardById(@ApiJsonObject(name = "voucherQueryCardByIdParams",
            value = {@ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "userId", value = "用户ID"),
                    @ApiJsonProperty(key = "voucherId", value = "会员卡ID")}) @RequestBody
                                                      JSONObject jsonParam) {
        String userId = (String) jsonParam.get("userId");
        String voucherId = (String) jsonParam.get("voucherId");
        Asserts.notBlank(userId, "用户ID");
        Asserts.notBlank(voucherId, "会员卡ID");
        try {
            return ResponseWrapper.succeed(fundsAccountService.getCardInfoByUserId(userId, voucherId));
        } catch (ApiException e) {
            log.error(String.format("[前端]获取会员卡信息不成功，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]获取会员卡信息出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }
    }

    @CurrentShop
    @RequestMapping(value = "user/voucher/card", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]获取会员卡信息", response = String.class)
    public ResponseWrapper getVoucherCard(@ApiJsonObject(name = "voucherQueryCardParams",
            value = {@ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "userId", value = "用户ID")}) @RequestBody
                                                  JSONObject jsonParam) {
        String userId = (String) jsonParam.get("userId");
        Asserts.notBlank(userId, "用户ID");
        try {
            return ResponseWrapper.succeed(fundsAccountService.getCardInfoByUserId(userId, null));
        } catch (ApiException e) {
            log.error(String.format("[前端]获取会员卡信息不成功，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]获取会员卡信息出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }

    }

    @CurrentShop
    @RequestMapping(value = "user/deposit/check", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[后台]查询银联充值结果", response = String.class)
    public ResponseWrapper depositCheck(@ApiJsonObject(name = "depositCheckParams",
            value = {@ApiJsonProperty(key = "shopId", value = "店铺ID"),
                    @ApiJsonProperty(key = "userId", value = "用户ID"),
                    @ApiJsonProperty(key = "thirdId", value = "三方ID")}) @RequestBody
                                                JSONObject jsonParam) {
        String userId = (String) jsonParam.get("userId");
        String thirdId = (String) jsonParam.get("thirdId");
        String shopId = (String) jsonParam.get("shopId");
        Asserts.notBlank(userId, "用户ID");
        Asserts.notBlank(shopId, "店铺");
        Asserts.notBlank(thirdId, "充值交易ID");
        try {
            return ResponseWrapper.succeed(fundsAccountService.getByThirdId(userId, thirdId));
        } catch (ApiException e) {
            log.error(String.format("[前端]查询银联充值结果不成功，参数:%s, 错误信息:%s", jsonParam.toJSONString(), e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        } catch (Exception e) {
            log.error(String.format("[前端]查询银联充值结果出错"), e);
            return ResponseWrapper.failed(ErrorCodeEnum.FL500);
        }

    }

    /**
     * 转增优惠券
     *
     * @param transferCouponsRequest 请求入参
     * @return
     */
    @CurrentShop
    @RequestMapping(value = "user/coupons/transfer", method = RequestMethod.POST)
    @ApiOperation(tags = "资金账户---所有金额相关的单位为:分", httpMethod = "POST", value = "[前台]转增优惠券", response = Boolean.class)
    public synchronized ResponseWrapper transferCoupon(@ApiParam @RequestBody TransferCouponsRequest transferCouponsRequest) {
        Asserts.notNull(transferCouponsRequest, "请求参数");
        Asserts.notBlank(transferCouponsRequest.getDisId(), "优惠券id");
        Asserts.notBlank(transferCouponsRequest.getMobile(), "受赠人手机号码");
        Asserts.notNull(transferCouponsRequest.getUserId(), "转增人id");

        try{
            fundsAccountService.transferCoupons2(transferCouponsRequest);
            return ResponseWrapper.succeed();
        }catch (ApiException e){
            log.error(String.format("[前端小程序]领取转赠优惠券失败，错误信息:%s",  e.getMessage()));
            return ResponseWrapper.failed(e.getCode(), e.getMessage());
        }
    }

    private void checkPayParams(CommonPayRequest commonPayRequest) {
        Asserts.notNull(commonPayRequest, "支付参数");

        Asserts.notNull(commonPayRequest.getShopId(), "店铺ID");
        Asserts.notNull(commonPayRequest.getUserId(), "用户ID");
        Asserts.naturalNumber(commonPayRequest.getTotalAmount(), "总计支付金额(分)");
        Asserts.naturalNumber(commonPayRequest.getAmount(), "实际支付金额(分)");
    }

    /**
     * 支付请求默认值处理
     *
     * @param commonPayRequest 支付请求
     */
    private void processDefaultVaule(CommonPayRequest commonPayRequest) {
        if (commonPayRequest.getReduceAmount() == null) {
            commonPayRequest.setReduceAmount(0);
        }
        if (commonPayRequest.getActivityAmount() == null) {
            Integer normalAmount = commonPayRequest.getNormalAmount();
            if (normalAmount == null) {
                commonPayRequest.setActivityAmount(commonPayRequest.getTotalAmount());
            } else {
                commonPayRequest.setActivityAmount(commonPayRequest.getTotalAmount() - normalAmount);
            }
        }
    }

    /**
     * 组装支付请求
     *
     * @param commonPayRequest 前端传递的支付参数
     * @return
     */
    private FundsPayDTO assembleFundsPay(CommonPayRequest commonPayRequest) {
        FundsPayDTO payDTO = new FundsPayDTO();
        BeanUtils.copyProperties(commonPayRequest, payDTO);
        String voucherId = commonPayRequest.getVoucherId();
        if (StringUtils.isNotBlank(voucherId)) {
            payDTO.setDiscountId(voucherId.split(";")[0]);
        }
        return payDTO;
    }
}
